//**********************************************************************************
// Klasse DrawPanel - ZeichenPanel für grafische Ausgabe des BAUMs
//
//
//**********************************************************************************
package binarytree.view.draw;

import binarytree.model.Node;
import binarytree.model.Tree;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;

import javax.swing.JPanel;

// *****************************************************
// Klasse : ZeichenPanel
// Eingabe : Keine
// Rückgabe: Keine
// Ausgabe : Keine
// *****************************************************
public class DrawPanel extends JPanel {

    // allgemeine Variablen für das Layout des Baums
    private int depth;
    private int pos;
    private Graphics2D g2D;
    private Tree tree;
    private final Font font;
    private int MAXLEVEL = 5;
    private int sheetWidth;
    private int sheetHeight;
    private boolean valuesOnOff = false;

    // Setter für Wertigkeiten anzeigen, ja/nein
    public void setValuesOnOff(boolean valuesOnOff) {
        this.valuesOnOff = valuesOnOff;
    }

    // *****************************************************
    // Konstruktor 
    // Eingabe : Keine
    // Rückgabe: Keine
    // Ausgabe : Keine
    // *****************************************************
    public DrawPanel() {
        font = new Font("Arial", Font.BOLD, 12);
        setBackground(Color.WHITE);
    }

    // *****************************************************
    // Klasse :  Malen des Baums
    // Eingabe : Keine
    // Rückgabe: Keine
    // Ausgabe : Keine
    // *****************************************************
    @Override
    public void paint(Graphics g) {
        setOpaque(false);
        super.paint(g);
        g2D = (Graphics2D) g;
        g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        if (tree != null && tree.getRoot() != null) {
            g2D.setFont(font);
            sheetHeight = this.getHeight();
            sheetWidth = this.getWidth() - 10;
            drawNode(tree.getRoot(), 1, sheetWidth / 2, sheetHeight / MAXLEVEL, sheetWidth / 2);
        }
    }

    // *****************************************************
    // Klasse : Malen der Knoten
    // Eingabe : Keine
    // Rückgabe: Keine
    // Ausgabe : Keine
    // *****************************************************
    @SuppressWarnings("empty-statement")
    public int[] drawNode(Node node, int level, int coordX, int coordY, int gapX) {
        int[] result = new int[4];
        int[] edge;
        if (level <= MAXLEVEL) {
            FontMetrics fontMetrics = g2D.getFontMetrics();
            int width = fontMetrics.stringWidth(node.toString());
            int height = fontMetrics.getHeight();
            int arcWidth = width + 16;
            int arcHeight = arcWidth;
            int offsetX = (arcWidth - width) / 2;
            int offsetY = (arcHeight / 2) + (height / 3);
            int posArcX = coordX - offsetX;
            int posArcY = (coordY - (sheetWidth / MAXLEVEL / 2)) - offsetY;
            g2D.drawArc(posArcX, posArcY, arcWidth, arcHeight, 0, 360);
            g2D.setColor(Color.WHITE);
            g2D.fillArc(posArcX, posArcY, arcWidth, arcHeight, 0, 360);
            g2D.setColor(Color.BLACK);
            g2D.drawString(node.toString(), coordX, coordY - (sheetWidth / MAXLEVEL / 2));
            if (valuesOnOff) {
                g2D.drawString(String.valueOf(node.value), coordX + 50, coordY - (sheetWidth / MAXLEVEL / 2));
            }
            double lineOffsetXY = Math.sin(Math.PI * 45 / 180) * arcWidth / 2;
            result[0] = posArcX + (arcWidth / 2 - (int) Math.round(lineOffsetXY));
            result[1] = posArcY + arcHeight / 2 - (int) Math.round(lineOffsetXY);
            result[2] = posArcX + arcWidth / 2 + (int) Math.round(lineOffsetXY);
            result[3] = posArcY + arcHeight / 2 - (int) Math.round(lineOffsetXY);
            if (node.hasLS()) {
                edge = drawNode(node.lS, level + 1, coordX - (gapX / 2), coordY + sheetHeight / MAXLEVEL, gapX / 2);
                lineOffsetXY = Math.sin(Math.PI * 45 / 180) * arcWidth / 2;
                if (edge != null) {
                    g2D.drawLine(posArcX + (arcWidth / 2 - (int) Math.round(lineOffsetXY)), posArcY + arcHeight / 2 + (int) Math.round(lineOffsetXY), edge[2], edge[3]);
                }
            }
            if (node.hasRS()) {
                edge = drawNode(node.rS, level + 1, coordX + (gapX / 2), coordY + sheetHeight / MAXLEVEL, gapX / 2);
                if (edge != null) {
                    g2D.drawLine(posArcX + arcWidth / 2 + (int) Math.round(lineOffsetXY), posArcY + arcHeight / 2 + (int) Math.round(lineOffsetXY), edge[0], edge[1]);
                }
            }

        } else {
            result = null;
        }
        ;
        return result;
    }

    public void setTree(Tree tree) {
        this.tree = tree;
    }

}
